package com.annet.token.annotation;

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.regex.Pattern;

/**
 * 字段初始化
 *
 * @author yh
 * @time 2020/6/20 下午 11:16
 */
@Inherited
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldInit {

    /**
     * 仅支持基本类型包装类、String、BigDecimal等
     *
     * @return 字段为null时初始化值
     * @see Character,String,Boolean,Byte,Short,Integer,Long,Float,Double, BigInteger ,BigDecimal
     */
    String value();

    class Inits {

        /**
         * 使用注解value值初始化字段，忽略转换异常
         *
         * @param t
         * @param <T>
         * @return
         */
        public static <T> T init(T t) {
            Class<?> clazz = t.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                String value = getInitValue(field);
                if (isNotEmpty(value)) {
                    field.setAccessible(true);
                    try {
                        if (null == field.get(t)) {
                            final Object v = valueOf(field, value);
                            if (null != v) {
                                field.set(t, v);
                            }
                        }
                    } catch (IllegalAccessException | NumberFormatException ignored) {
                    }
                }
            }
            return t;
        }

        private static String getInitValue(Field field) {
            FieldInit init = field.getAnnotation(FieldInit.class);
            if (null != init) {
                return init.value();
            }
            return null;
        }

        private static boolean isNotEmpty(String value) {
            return null != value && value.length() != 0;
        }

        private static Object valueOf(Field field, String value) {
            Object obj = null;
            switch (field.getType().getName()) {
                case "java.lang.String":
                    obj = value;
                    break;
                case "java.lang.Character":
                    obj = value.charAt(0);
                    break;
                case "java.lang.Boolean":
                    if (Pattern.matches("(\\d+)|(true|false)", value)) {
                        obj = Boolean.valueOf(value);
                    }
                    break;
                case "java.lang.Byte":
                    if (Pattern.matches("^[+\\-]?\\d+$", value)) {
                        obj = Byte.valueOf(value);
                    }
                    break;
                case "java.lang.Short":
                    if (Pattern.matches("^[+\\-]?\\d+$", value)) {
                        obj = Short.valueOf(value);
                    }
                    break;
                case "java.lang.Integer":
                    if (Pattern.matches("^[+\\-]?\\d+$", value)) {
                        obj = Integer.valueOf(value);
                    }
                    break;
                case "java.lang.Long":
                    if (Pattern.matches("^[+\\-]?\\d+[lL]?$", value)) {
                        obj = Long.valueOf(value);
                    }
                    break;
                case "java.lang.Float":
                    if (Pattern.matches("^[+\\-]?\\d+\\.?\\d*[fF]?$", value)) {
                        obj = Float.valueOf(value);
                    }
                    break;
                case "java.lang.Double":
                    if (Pattern.matches("^[+\\-]?\\d+\\.?\\d*[fF]?$", value)) {
                        obj = Double.valueOf(value);
                    }
                    break;
                case "java.math.BigInteger":
                    if (Pattern.matches("^[+\\-]?\\d+$", value)) {
                        obj = new BigInteger(value);
                    }
                    break;
                case "java.math.BigDecimal":
                    if (Pattern.matches("^[+\\-]?\\d+\\.?\\d*[fF]?$", value)) {
                        obj = new BigDecimal(value);
                    }
                    break;
            }
            return obj;
        }

    }

}
